#!/usr/bin/env python
# encoding: utf-8
"""
TwoPartySimulation.py

Created by Drew Conway <agc282@nyu.edu> on 2008-10-07.
Copyright (c) 2008. All rights reserved, see GNU LGPL.

PyVote is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.


Version = 0.1a
"""

import sys
import os
from TwoPartyLegislature import *
import networkx
from scipy import random
import pylab as P

# Creates network object of voting results (Requires NetworkX)
def create_voting_network(legislature,passed_only=False):
	G=networkx.Graph()
	num_legislators=legislature.size()
	if passed_only:
		for b in legislature.get_passed_bills():
			for a in legislature.legislators():
				r=a.get_record()
				if r[b.get_bill_num()]>0:
					G.add_edge(a.id,num_legislators+b.get_bill_num())
	else:
		for a in legislature.legislators():
			r=a.get_record()
			for b in r.keys():
				if r[b]>0:
					G.add_edge(a.id,num_legislators+b)
	return G
	
	
def committee_work(legislature,committees):
	bills=[]	# Bill produced by the committees
	for i in range(0,len(committees)):
		c=committees[i]
		the_members=c.get_members()
		setter=the_members[0]
		while legislature.get_agent(setter).get_party() != legislature.majority():
			random.shuffle(the_members)
			setter=the_members[0]
		B=c.make_bill(legislature,setter)
		if B is not None:
			B.set_bill_num(i)
			bills.append(B)
	return bills
	
def get_bimodal(size1,size2):
	norm1=random.normal(0.0,size=size1)
	norm2=random.normal(0.0,size=size2)
	hist1=list(P.histogram(norm1,bins=5)[0])
	hist2=list(P.histogram(norm2,bins=5)[0])
	return hist1+hist2
	
def get_uniform(size):
	if size<10:
		raise ValueError('Legislature size must be > 10')
	else:
		R=size%10
		dist=[]
		bin_size=size/10
		for i in range(0,10):
			dist.append(bin_size)
		if R<1:
			return dist
		else:
			used_bins=[]
			for p in range(0,R):
				random_bin=int(random.randint(0,9))
				while used_bins.count(random_bin)>0:
					random_bin=int(random.randint(0,9))
				dist[random_bin]+=1
				used_bins.append(random_bin)
			return dist
		
	

def main():
	num_agents=434
	committee_size=35
	num_committees=10
	# Change the default tolerance function
	#new_tol= lambda t: 0.5*t
	
	# Random bimodal ideological distribution
	bimo_dist=get_bimodal(num_agents/2,num_agents/2)
	
	# Random normal idelogical distribution
	ran_dist=random.normal(0.1,size=num_agents)
	norm_dist=P.histogram(ran_dist)[0]
	
	# Strict uniform distribution
	strict_uni=get_uniform(num_agents)
	
	# Three random ideological distributions options for testing
	#L=TwoPartyLegislature(num_agents,norm_dist)	# Normal distribution
	#L=TwoPartyLegislature(num_agents,bimo_dist)	# Bimodal 
	L=TwoPartyLegislature(num_agents,strict_uni)	# Strict uniform based on number of agents % 10
	#L=TwoPartyLegislature(num_agents)				# Random uniform
	L.info()
	L.show_ideology_distribution()
	
	committee_list=[]
	
	for i in range(0,num_committees):
		committee_list.append(Committee(L,committee_size))
		
	bills=committee_work(L,committee_list)

	# Distance function for calculating 1-dimensional utility
	d=lambda x,y: abs(x-y)
	
	# Begin voting procedure
	for v in range(0, len(bills)):
		B=bills[v]
		bill_proposed_ideology=B.get_ideology()
		committee_status_quo=B.get_status_quo()
		for a in L.legislators():
		# Now ask each legislator if it will vote for the bill.  An agent decides if changing the 
		# status quo of a committee to the new proposed ideology increases their utility.  That is, 
		# if the distance from its ideology to the new ideology is shortened by the new proposal.
			if a.vote(bill_proposed_ideology,committee_status_quo,probabilistic=True):
			# If the distance is greater between the agent's ideology and the status quo than that and the newly
			# proposed ideology, then the agent will vote for the bill because its utility will be increased
				a.add_record(v,1)
				B.add_record(a,1)
			else:
				a.add_record(v,0)
				B.add_record(1,0)
				
		if (B.num_conservative_yays()+B.num_liberal_yays())>(num_agents/2):
			B.set_passage(True)
			for a in L.legislators(): 
				current_agent_ideology=a.get_ideology()
				a.set_utility(d(current_agent_ideology,bill_proposed_ideology)**2)
		else:
			B.set_passage(False)
			for a in L.legislators():
				current_agent_ideology=a.get_ideology()
				a.set_utility(d(current_agent_ideology,committee_status_quo)**2)
		L.add_bill(B)
	
	L.show_utility_scatter()
		
	passed=L.get_passed_bills()
	num_bills_passed=len(passed)
	# Basic Output
	print '--- COMMITTEE ---'
	for C in committee_list:
		C.info()
		print''
		
	print '--- BILL INFO ---'
	for B in bills:
		B.info()
		print ''
	
	P.show()

	
if __name__ == '__main__':
    main()
